#include "LogItem.hpp"
#include "Util.hpp"
#ifdef LOGGER_FORMAT_STRING
#include "../3rdparty/nlohmann/json.hpp"
#endif

#include <iostream>
#include <sstream>
#include <functional>

namespace cybertron {
	LogItemV1::LogItemV1()
	{
		_version = 1;
		_time_stamp = 0;
		_category = _producer = _pid = _level = _message = "";
	}

	LogItemV1::LogItemV1(const LogItemV1 & item)
	{
		_version = item._version;
		_time_stamp = item._time_stamp;
		_pid = item._pid;

		_category = item._category;
		_producer = item._producer;
		_level = item._level;

		_message = item._message;
	}

	LogItemV1::LogItemV1(const std::string & category, const std::string & producer, const std::string & level, const std::string & message)
	{
		_version = 1;
		_time_stamp = Util::time_now_ms();
		_pid = std::to_string(Util::get_current_pid());

		_category = category;
		_producer = producer;
		_level = level;

		_message = message;
		_message = Util::replace(_message, "\n", "\\n");
		_message = Util::replace(_message, "\r", "\\r");
	}

	std::string LogItemV1::to_net_message()
	{
		std::string output = "v1";
		output += _message_delimiter;
		output += std::to_string(_time_stamp);
		output += _message_delimiter;
		output += _category;
		output += _message_delimiter;
		output += _producer;
		output += _message_delimiter;
		output += _pid;
		output += _message_delimiter;
		output += _level;
		output += _message_delimiter;
		//output += _code;
		//output += _message_delimiter;
		output += _message;

		return output;
	}
	int LogItemV1::from_net_message(const std::string message)
	{
		std::istringstream ss(message);

		std::string buf;
		if (std::getline(ss, buf, _message_delimiter)) {
			// skip "v[n]"
		}
		else {
			return -1;
		}

		if (std::getline(ss, buf, _message_delimiter)) {
			_time_stamp = std::strtoll(buf.c_str(), 0, 10);
		}
		else {
			return -1;
		}

		if (std::getline(ss, buf, _message_delimiter)) {
			_category = buf;
		}
		else {
			return -1;
		}

		if (std::getline(ss, buf, _message_delimiter)) {
			_producer = buf;
		}
		else {
			return -1;
		}

		if (std::getline(ss, buf, _message_delimiter)) {
			_pid = buf;
		}
		else {
			return -1;
		}

		if (std::getline(ss, buf, _message_delimiter)) {
			_level = buf;
		}
		else {
			return -1;
		}

		//if (std::getline(ss, buf, _message_delimiter)) {
		//	_code = buf;
		//}
		//else {
		//	return -1;
		//}

		if (std::getline(ss, buf, _message_delimiter)) {
			_message = buf;
		}
		else {
			return -1;
		}
		return 0;
	}

	std::string LogItemV1::to_file_line()
	{
		std::string output = "v1";
		output += _file_line_delimiter;
		output += Util::format_datetime_ms(_time_stamp);
		output += _file_line_delimiter;
		output += Util::replace(_category, _file_line_delimiter, "_");
		output += _file_line_delimiter;
		output += Util::replace(_producer, _file_line_delimiter, "_");
		output += _file_line_delimiter;
		output += _pid;
		output += _file_line_delimiter;
		output += _level;
		output += _file_line_delimiter;
		//output += _code;
		//output += _file_line_delimiter;
		output += _message;

		return output;
	}

	std::string LogItemV1::to_local_file_line()
	{
		std::string output = Util::format_datetime_ms(_time_stamp);
		//output += _file_line_delimiter;
		//output += _category;
		//output += _file_line_delimiter;
		//output += _producer;
		output += _file_line_delimiter;
		output += "[" + _pid + "]";
		output += _file_line_delimiter;
		output += _level;
		output += _file_line_delimiter;
		//output += _code;
		//output += _file_line_delimiter;
		output += _message;

		return output;
	}

	int LogItemV1::from_file_line(const std::string message)
	{
		return 0;
	}

	size_t LogItemV1::category_id()
	{
		return std::hash<std::string>{}(_category);
	}

	LogItem *LogItemBuilder::build_item_from_net_message(const std::string message)
	{
		if (message.find("v1") == 0) {
			return new LogItemV1();
		}
		else {
			return nullptr;
		}
	}
}